use chrono::Local;
use std::io;
use tracing::level_filters::LevelFilter;
use tracing::{Level, Subscriber};
use tracing_appender::non_blocking;
use tracing_appender::rolling::{RollingFileAppender, Rotation};
use tracing_subscriber::fmt::format::Writer;
use tracing_subscriber::fmt::time::{ChronoLocal, FormatTime};
use tracing_subscriber::layer::SubscriberExt;
use tracing_subscriber::util::SubscriberInitExt;
use tracing_subscriber::{filter, fmt, registry, Layer, Registry};

/// 按时间滚动生成日志
/// * rolling::never       生成一个文件
/// * rolling::daily       一天生成一个文件
/// * rolling::hourly      一小时生成一个文件
/// * rolling::minutely    一分钟生成一个文件
///
/// 非阻塞日志记录
pub fn init_tracing_log_non_blocking() {
    // let mut vec = Vec::new();

    // 创建非阻塞控制台打印
    let (stderr, guard) = non_blocking(io::stderr());
    // vec.push(guard);
    let guard = Box::new(guard);
    Box::leak(guard);

    let console_layer = fmt::layer()
        // 自定义数据时间格式
        .with_timer(LocalFormatTime::default())
        // 线程名
        .with_thread_names(true)
        // .with_writer(io::stderr);
        .with_writer(stderr)
        // 只记录INFO及以上级别的日志
        .with_filter(LevelFilter::INFO);

    // 输出到文件中
    //let debug_file_appender = rolling::minutely("logs", "debug.log");
    let debug_file_appender = RollingFileAppender::builder()
        // 最大保留60个文件
        .max_log_files(60)
        // 一天生成一个文件
        .rotation(Rotation::DAILY)
        // 文件名前缀
        .filename_prefix("debug")
        // 文件名后缀
        .filename_suffix("log")
        // 文件所在目录
        .build("./logs/debug")
        .expect("initializing rolling file appender failed");

    // 不知为何创建非阻塞写入器后无法写入到文件
    // 原因：需要确保debug_file_appender和guard活的足够久
    let (debug_file_appender, guard) = non_blocking(debug_file_appender);
    // vec.push(guard);
    let guard = Box::new(guard);
    Box::leak(guard);

    let debug_file_layer = fmt::layer()
        .with_timer(LocalFormatTime::default())
        .with_thread_names(true)
        .with_ansi(false)
        .with_writer(debug_file_appender)
        .with_filter(LevelFilter::DEBUG) // 日志级别
        .with_filter(filter::filter_fn(|metadata| {
            // 只记录log-lib::tracing_log模块下的日志
            // metadata.target() = "log-lib::tracing_log"
            // 只记录DEBUG级别的日志
            metadata.level() == &Level::DEBUG
        }));

    // 输出到文件中
    let info_file_appender = RollingFileAppender::builder()
        .max_log_files(60)
        .rotation(Rotation::DAILY)
        .filename_prefix("info")
        .filename_suffix("log")
        .build("./logs/info")
        .expect("initializing rolling file appender failed");

    // 不知为何创建非阻塞写入器后无法写入到文件
    // 原因需要确保info_file_appender和_guard活的足够久
    let (info_file_appender, guard) = non_blocking(info_file_appender);
    // vec.push(guard);
    let guard = Box::new(guard);
    Box::leak(guard);

    let info_file_layer = fmt::layer()
        .with_ansi(false)
        .with_timer(LocalFormatTime::default())
        .with_thread_names(true)
        .with_writer(info_file_appender)
        .with_filter(LevelFilter::INFO)
        .with_filter(filter::filter_fn(|metadata| {
            metadata.level() == &Level::INFO
        }));

    // 输出到文件中
    let error_file_appender = RollingFileAppender::builder()
        .max_log_files(60)
        .rotation(Rotation::DAILY)
        .filename_prefix("error")
        .filename_suffix("log")
        .build("./logs/error")
        .expect("initializing rolling file appender failed");

    let (error_file_appender, guard) = non_blocking(error_file_appender);
    // vec.push(guard);
    let guard = Box::new(guard);
    Box::leak(guard);

    let error_file_layer = fmt::layer()
        .with_ansi(false)
        .with_timer(LocalFormatTime::new("%Y-%m-%d %H:%M:%S"))
        .with_thread_names(true)
        .with_writer(error_file_appender)
        .with_filter(LevelFilter::ERROR)
        .with_filter(filter::filter_fn(|metadata| {
            metadata.level() == &Level::ERROR
        }));

    // 注册
    Registry::default()
        .with(console_layer)
        .with(debug_file_layer)
        .with(info_file_layer)
        .with(error_file_layer)
        // 指定日志级别
        // .with(LevelFilter::INFO)
        .init();

    // vec
}

/// 按时间滚动生成日志
/// * rolling::never       生成一个文件
/// * rolling::daily       一天生成一个文件
/// * rolling::hourly      一小时生成一个文件
/// * rolling::minutely    一分钟生成一个文件
///
/// 阻塞日志记录
pub fn init_tracing_log() {
    let timer = ChronoLocal::new(String::from("%Y-%m-%d %H:%M:%S"));

    let console_layer = fmt::layer()
        // 自定义数据时间格式
        .with_timer(timer.clone())
        // 线程名
        .with_thread_names(true)
        // 输出到标准的成错误输出
        .with_writer(io::stderr)
        // 只记录INFO及以上级别的日志
        .with_filter(LevelFilter::INFO);

    // 输出到文件中
    //let debug_file_appender = rolling::minutely("logs", "debug.log");
    let debug_file_appender = RollingFileAppender::builder()
        // 最大保留60个文件
        .max_log_files(60)
        // 一天生成一个文件
        .rotation(Rotation::DAILY)
        // 文件名前缀
        .filename_prefix("debug")
        // 文件名后缀
        .filename_suffix("log")
        // 文件所在目录
        .build("./logs/debug")
        .expect("initializing rolling file appender failed");

    let debug_file_layer = fmt::layer()
        .with_timer(timer.clone())
        .with_thread_names(true)
        .with_ansi(false)
        .with_writer(debug_file_appender)
        .with_filter(LevelFilter::DEBUG) // 日志级别
        .with_filter(filter::filter_fn(|metadata| {
            // 只记录log-lib::tracing_log模块下的日志
            // metadata.target() = "log-lib::tracing_log"
            // 只记录DEBUG级别的日志
            metadata.level() == &Level::DEBUG
        }));

    // 输出到文件中
    let info_file_appender = RollingFileAppender::builder()
        .max_log_files(60)
        .rotation(Rotation::DAILY)
        .filename_prefix("info")
        .filename_suffix("log")
        .build("./logs/info")
        .expect("initializing rolling file appender failed");

    let info_file_layer = fmt::layer()
        .with_ansi(false)
        .with_timer(timer.clone())
        .with_thread_names(true)
        .with_writer(info_file_appender)
        .with_filter(LevelFilter::INFO)
        .with_filter(filter::filter_fn(|metadata| {
            metadata.level() == &Level::INFO
        }));

    // 输出到文件中
    // let error_file_appender = RollingFileAppender::builder()
    //     .max_log_files(60)
    //     .rotation(Rotation::DAILY)
    //     .filename_prefix("error")
    //     .filename_suffix("log")
    //     .build("./logs/error")
    //     .expect("initializing rolling file appender failed");
    // let error_file_layer = fmt::layer()
    //     .with_ansi(false)
    //     .with_timer(timer.clone())
    //     .with_thread_names(true)
    //     .with_writer(error_file_appender)
    //     .with_filter(LevelFilter::ERROR);
    let error_file_layer = get_layer();

    // 注册
    Registry::default()
        .with(console_layer)
        .with(debug_file_layer)
        .with(info_file_layer)
        .with(error_file_layer)
        .init();
}

/// 自定义时间输出格式
struct LocalFormatTime {
    fomat: String,
}

impl LocalFormatTime {
    fn new(fomat: &str) -> LocalFormatTime {
        LocalFormatTime {
            fomat: String::from(fomat),
        }
    }
}

impl Default for LocalFormatTime {
    fn default() -> Self {
        LocalFormatTime {
            fomat: String::from("%Y-%m-%d %H:%M:%S"),
        }
    }
}

impl FormatTime for LocalFormatTime {
    fn format_time(&self, w: &mut Writer<'_>) -> std::fmt::Result {
        let format = Local::now().format(self.fomat.as_str());
        write!(w, "{}", format.to_string())
    }
}


fn get_layer<S>() -> impl Layer<S>
where 
    S: Subscriber + for<'span> registry::LookupSpan<'span> + 'static,
{
    let timer = ChronoLocal::new(String::from("%Y-%m-%d %H:%M:%S"));
    // 输出到文件中
    let error_file_appender = RollingFileAppender::builder()
        .max_log_files(60)
        .rotation(Rotation::DAILY)
        .filename_prefix("error")
        .filename_suffix("log")
        .build("./logs/error")
        .expect("initializing rolling file appender failed");
     fmt::layer()
        .with_ansi(false)
        .with_timer(timer.clone())
        .with_thread_names(true)
        .with_writer(error_file_appender)
        .with_filter(LevelFilter::ERROR)
}